from typing import Optional, List, Dict, Any, Tuple
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, desc, asc, func, text
from datetime import datetime, timedelta
import logging
import json

from app.domains.models import Alert, AlertRule, NotificationChannel, NotificationLog, Device, User
from app.domains.alert.schemas import (
    AlertRuleCreate, AlertRuleUpdate, AlertRuleListQuery,
    AlertCreate, AlertUpdate, AlertListQuery,
    NotificationChannelCreate, NotificationChannelUpdate,
    AlertBatchOperation, TestAlertRequest
)
from app.shared.exceptions.base import (
    NotFoundException, ConflictException, ValidationException, BusinessException
)
from app.shared.constants.status_codes import BusinessCode
from app.shared.constants.enums import AlertLevel, AlertType, NotificationType
from app.shared.utils.datetime import utc_now
from app.shared.utils.formatter import generate_short_id

logger = logging.getLogger(__name__)


class AlertRuleRepository:
    """告警规则数据访问层"""
    
    def __init__(self, db: Session):
        self.db = db
    
    def get_by_id(self, rule_id: int) -> Optional[AlertRule]:
        """根据ID获取告警规则"""
        return self.db.query(AlertRule).filter(AlertRule.id == rule_id).first()
    
    def get_by_name(self, rule_name: str) -> Optional[AlertRule]:
        """根据规则名称获取告警规则"""
        return self.db.query(AlertRule).filter(AlertRule.rule_name == rule_name).first()
    
    def create(self, rule_data: AlertRuleCreate, created_by: int) -> AlertRule:
        """创建告警规则"""
        rule = AlertRule(
            rule_name=rule_data.rule_name,
            description=rule_data.description,
            alert_type=rule_data.alert_type,
            level=rule_data.level,
            is_enabled=rule_data.is_enabled,
            condition_expression=rule_data.condition_expression,
            notification_template=rule_data.notification_template,
            notification_types=rule_data.notification_types,
            notification_recipients=rule_data.notification_recipients,
            check_interval=rule_data.check_interval,
            max_alert_frequency=rule_data.max_alert_frequency,
            device_types=rule_data.device_types,
            locations=rule_data.locations,
            created_by=created_by,
            created_at=utc_now(),
            updated_at=utc_now(),
            trigger_count=0
        )
        
        self.db.add(rule)
        self.db.commit()
        self.db.refresh(rule)
        
        logger.info(f"✅ 告警规则创建成功: {rule.rule_name}")
        return rule
    
    def update(self, rule: AlertRule, rule_data: AlertRuleUpdate) -> AlertRule:
        """更新告警规则"""
        update_data = rule_data.dict(exclude_unset=True)
        
        for field, value in update_data.items():
            setattr(rule, field, value)
        
        rule.updated_at = utc_now()
        
        self.db.commit()
        self.db.refresh(rule)
        
        logger.info(f"✅ 告警规则更新成功: {rule.rule_name}")
        return rule
    
    def get_list(self, query: AlertRuleListQuery) -> Tuple[List[AlertRule], int]:
        """获取告警规则列表"""
        q = self.db.query(AlertRule)
        
        # 搜索条件
        if query.search:
            search_term = f"%{query.search}%"
            q = q.filter(or_(
                AlertRule.rule_name.like(search_term),
                AlertRule.description.like(search_term)
            ))
        
        # 告警类型筛选
        if query.alert_type:
            q = q.filter(AlertRule.alert_type == query.alert_type)
        
        # 告警级别筛选
        if query.level:
            q = q.filter(AlertRule.level == query.level)
        
        # 启用状态筛选
        if query.is_enabled is not None:
            q = q.filter(AlertRule.is_enabled == query.is_enabled)
        
        # 排序
        sort_column = getattr(AlertRule, query.sort_by, AlertRule.created_at)
        if query.sort_order == "desc":
            q = q.order_by(desc(sort_column))
        else:
            q = q.order_by(asc(sort_column))
        
        # 获取总数
        total = q.count()
        
        # 分页
        offset = (query.page - 1) * query.page_size
        rules = q.offset(offset).limit(query.page_size).all()
        
        return rules, total
    
    def delete(self, rule: AlertRule) -> bool:
        """删除告警规则"""
        try:
            self.db.delete(rule)
            self.db.commit()
            
            logger.info(f"✅ 告警规则删除成功: {rule.rule_name}")
            return True
        except Exception as e:
            logger.error(f"❌ 告警规则删除失败: {e}")
            self.db.rollback()
            return False
    
    def get_enabled_rules(self) -> List[AlertRule]:
        """获取启用的告警规则"""
        return self.db.query(AlertRule).filter(AlertRule.is_enabled == True).all()
    
    def increment_trigger_count(self, rule: AlertRule):
        """增加触发次数"""
        rule.trigger_count += 1
        rule.last_triggered_at = utc_now()
        self.db.commit()


class AlertRepository:
    """告警数据访问层"""
    
    def __init__(self, db: Session):
        self.db = db
    
    def get_by_id(self, alert_id: int) -> Optional[Alert]:
        """根据ID获取告警"""
        return self.db.query(Alert).filter(Alert.id == alert_id).first()
    
    def create(self, alert_data: AlertCreate) -> Alert:
        """创建告警"""
        alert_number = f"ALT{generate_short_id()}"
        
        alert = Alert(
            alert_number=alert_number,
            title=alert_data.title,
            content=alert_data.content,
            level=alert_data.level,
            alert_type=alert_data.alert_type,
            device_id=alert_data.device_id,
            rule_id=alert_data.rule_id,
            source_data=alert_data.source_data,
            is_resolved=False,
            created_at=utc_now(),
            updated_at=utc_now()
        )
        
        self.db.add(alert)
        self.db.commit()
        self.db.refresh(alert)
        
        logger.info(f"✅ 告警创建成功: {alert.alert_number} - {alert.title}")
        return alert
    
    def update(self, alert: Alert, alert_data: AlertUpdate, resolved_by: Optional[int] = None) -> Alert:
        """更新告警"""
        if alert_data.is_resolved and not alert.is_resolved:
            alert.is_resolved = True
            alert.resolved_by = resolved_by
            alert.resolved_at = utc_now()
            alert.resolution_notes = alert_data.resolution_notes
        
        alert.updated_at = utc_now()
        
        self.db.commit()
        self.db.refresh(alert)
        
        logger.info(f"✅ 告警更新成功: {alert.alert_number}")
        return alert
    
    def get_list(self, query: AlertListQuery) -> Tuple[List[Alert], int]:
        """获取告警列表"""
        q = self.db.query(Alert).outerjoin(Device, Alert.device_id == Device.id)
        
        # 搜索条件
        if query.search:
            search_term = f"%{query.search}%"
            q = q.filter(or_(
                Alert.alert_number.like(search_term),
                Alert.title.like(search_term),
                Alert.content.like(search_term),
                Device.device_code.like(search_term),
                Device.device_name.like(search_term)
            ))
        
        # 告警级别筛选
        if query.level:
            q = q.filter(Alert.level == query.level)
        
        # 告警类型筛选
        if query.alert_type:
            q = q.filter(Alert.alert_type == query.alert_type)
        
        # 设备筛选
        if query.device_id:
            q = q.filter(Alert.device_id == query.device_id)
        
        # 解决状态筛选
        if query.is_resolved is not None:
            q = q.filter(Alert.is_resolved == query.is_resolved)
        
        # 规则筛选
        if query.rule_id:
            q = q.filter(Alert.rule_id == query.rule_id)
        
        # 日期范围筛选
        if query.start_date:
            q = q.filter(Alert.created_at >= query.start_date)
        
        if query.end_date:
            q = q.filter(Alert.created_at <= query.end_date)
        
        # 排序
        sort_column = getattr(Alert, query.sort_by, Alert.created_at)
        if query.sort_order == "desc":
            q = q.order_by(desc(sort_column))
        else:
            q = q.order_by(asc(sort_column))
        
        # 获取总数
        total = q.count()
        
        # 分页
        offset = (query.page - 1) * query.page_size
        alerts = q.offset(offset).limit(query.page_size).all()
        
        return alerts, total
    
    def get_by_ids(self, alert_ids: List[int]) -> List[Alert]:
        """根据ID列表获取告警"""
        return self.db.query(Alert).filter(Alert.id.in_(alert_ids)).all()
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取告警统计数据"""
        # 状态统计
        total_count = self.db.query(Alert).count()
        resolved_count = self.db.query(Alert).filter(Alert.is_resolved == True).count()
        unresolved_count = total_count - resolved_count
        
        # 级别统计
        level_stats = self.db.query(
            Alert.level,
            func.count(Alert.id).label('count')
        ).group_by(Alert.level).all()
        
        critical_count = sum(stat.count for stat in level_stats if stat.level == AlertLevel.CRITICAL)
        high_count = sum(stat.count for stat in level_stats if stat.level == AlertLevel.ERROR)
        
        # 类型统计
        type_stats = self.db.query(
            Alert.alert_type,
            func.count(Alert.id).label('count')
        ).group_by(Alert.alert_type).all()
        
        # 平均解决时长（已解决的告警）
        resolved_alerts = self.db.query(Alert).filter(
            and_(
                Alert.is_resolved == True,
                Alert.resolved_at.isnot(None),
                Alert.created_at.isnot(None)
            )
        ).all()
        
        if resolved_alerts:
            total_resolution_time = sum([
                (alert.resolved_at - alert.created_at).total_seconds() / 3600
                for alert in resolved_alerts
            ])
            avg_resolution_time = total_resolution_time / len(resolved_alerts)
        else:
            avg_resolution_time = 0
        
        # 解决率
        resolution_rate = (resolved_count / total_count * 100) if total_count > 0 else 0
        
        return {
            'total_count': total_count,
            'unresolved_count': unresolved_count,
            'resolved_count': resolved_count,
            'critical_count': critical_count,
            'high_count': high_count,
            'avg_resolution_time': round(avg_resolution_time, 2),
            'resolution_rate': round(resolution_rate, 2),
            'by_type': {stat.alert_type.value: stat.count for stat in type_stats},
            'by_level': {stat.level.value: stat.count for stat in level_stats}
        }


class NotificationChannelRepository:
    """通知渠道数据访问层"""
    
    def __init__(self, db: Session):
        self.db = db
    
    def get_by_id(self, channel_id: int) -> Optional[NotificationChannel]:
        """根据ID获取通知渠道"""
        return self.db.query(NotificationChannel).filter(NotificationChannel.id == channel_id).first()
    
    def create(self, channel_data: NotificationChannelCreate, created_by: int) -> NotificationChannel:
        """创建通知渠道"""
        channel = NotificationChannel(
            channel_name=channel_data.channel_name,
            channel_type=channel_data.channel_type,
            is_enabled=channel_data.is_enabled,
            configuration=channel_data.configuration,
            created_by=created_by,
            created_at=utc_now(),
            updated_at=utc_now(),
            success_count=0,
            failure_count=0
        )
        
        self.db.add(channel)
        self.db.commit()
        self.db.refresh(channel)
        
        logger.info(f"✅ 通知渠道创建成功: {channel.channel_name}")
        return channel
    
    def update(self, channel: NotificationChannel, channel_data: NotificationChannelUpdate) -> NotificationChannel:
        """更新通知渠道"""
        update_data = channel_data.dict(exclude_unset=True)
        
        for field, value in update_data.items():
            setattr(channel, field, value)
        
        channel.updated_at = utc_now()
        
        self.db.commit()
        self.db.refresh(channel)
        
        logger.info(f"✅ 通知渠道更新成功: {channel.channel_name}")
        return channel
    
    def get_enabled_channels(self, channel_type: Optional[NotificationType] = None) -> List[NotificationChannel]:
        """获取启用的通知渠道"""
        q = self.db.query(NotificationChannel).filter(NotificationChannel.is_enabled == True)
        
        if channel_type:
            q = q.filter(NotificationChannel.channel_type == channel_type)
        
        return q.all()


class AlertService:
    """告警业务逻辑层"""
    
    def __init__(self, db: Session):
        self.db = db
        self.rule_repository = AlertRuleRepository(db)
        self.alert_repository = AlertRepository(db)
        self.channel_repository = NotificationChannelRepository(db)
    
    def create_alert_rule(self, rule_data: AlertRuleCreate, created_by: int) -> AlertRule:
        """创建告警规则"""
        # 检查规则名称是否已存在
        if self.rule_repository.get_by_name(rule_data.rule_name):
            raise ConflictException(f"告警规则名称 {rule_data.rule_name} 已存在")
        
        return self.rule_repository.create(rule_data, created_by)
    
    def get_alert_rule_by_id(self, rule_id: int) -> AlertRule:
        """根据ID获取告警规则"""
        rule = self.rule_repository.get_by_id(rule_id)
        if not rule:
            raise NotFoundException("告警规则", rule_id)
        return rule
    
    def update_alert_rule(self, rule_id: int, rule_data: AlertRuleUpdate) -> AlertRule:
        """更新告警规则"""
        rule = self.get_alert_rule_by_id(rule_id)
        
        # 如果要更新规则名称，检查是否冲突
        if rule_data.rule_name and rule_data.rule_name != rule.rule_name:
            if self.rule_repository.get_by_name(rule_data.rule_name):
                raise ConflictException(f"告警规则名称 {rule_data.rule_name} 已存在")
        
        return self.rule_repository.update(rule, rule_data)
    
    def delete_alert_rule(self, rule_id: int) -> bool:
        """删除告警规则"""
        rule = self.get_alert_rule_by_id(rule_id)
        
        # 检查是否有关联的告警
        alert_count = self.db.query(Alert).filter(Alert.rule_id == rule_id).count()
        if alert_count > 0:
            raise BusinessException(
                BusinessCode.OPERATION_FAILED,
                f"无法删除规则，存在 {alert_count} 个关联的告警"
            )
        
        return self.rule_repository.delete(rule)
    
    def get_alert_rule_list(self, query: AlertRuleListQuery) -> Tuple[List[AlertRule], int]:
        """获取告警规则列表"""
        return self.rule_repository.get_list(query)
    
    def create_alert(self, alert_data: AlertCreate) -> Alert:
        """创建告警"""
        # 验证设备是否存在
        if alert_data.device_id:
            device = self.db.query(Device).filter(Device.id == alert_data.device_id).first()
            if not device:
                raise NotFoundException("设备", alert_data.device_id)
        
        # 验证告警规则是否存在
        if alert_data.rule_id:
            rule = self.rule_repository.get_by_id(alert_data.rule_id)
            if not rule:
                raise NotFoundException("告警规则", alert_data.rule_id)
            
            # 增加规则触发次数
            self.rule_repository.increment_trigger_count(rule)
        
        alert = self.alert_repository.create(alert_data)
        
        # 发送通知
        # 这里可以添加异步任务来发送通知
        # await self._send_notifications(alert)
        
        return alert
    
    def get_alert_by_id(self, alert_id: int) -> Alert:
        """根据ID获取告警"""
        alert = self.alert_repository.get_by_id(alert_id)
        if not alert:
            raise NotFoundException("告警", alert_id)
        return alert
    
    def update_alert(self, alert_id: int, alert_data: AlertUpdate, user_id: int) -> Alert:
        """更新告警"""
        alert = self.get_alert_by_id(alert_id)
        
        return self.alert_repository.update(alert, alert_data, user_id if alert_data.is_resolved else None)
    
    def get_alert_list(self, query: AlertListQuery) -> Tuple[List[Alert], int]:
        """获取告警列表"""
        return self.alert_repository.get_list(query)
    
    def batch_operation(self, operation_data: AlertBatchOperation, user_id: int) -> Dict[str, Any]:
        """批量操作告警"""
        alerts = self.alert_repository.get_by_ids(operation_data.alert_ids)
        
        if len(alerts) != len(operation_data.alert_ids):
            found_ids = [alert.id for alert in alerts]
            missing_ids = [id for id in operation_data.alert_ids if id not in found_ids]
            raise ValidationException(f"告警不存在: {missing_ids}")
        
        results = {
            "success": [],
            "failed": [],
            "total": len(alerts)
        }
        
        for alert in alerts:
            try:
                if operation_data.operation == "resolve":
                    if not alert.is_resolved:
                        notes = operation_data.params.get("resolution_notes") if operation_data.params else None
                        alert_data = AlertUpdate(is_resolved=True, resolution_notes=notes)
                        self.alert_repository.update(alert, alert_data, user_id)
                        results["success"].append(alert.id)
                    else:
                        results["failed"].append({
                            "alert_id": alert.id,
                            "reason": "告警已解决"
                        })
                        
                elif operation_data.operation == "unresolve":
                    if alert.is_resolved:
                        alert.is_resolved = False
                        alert.resolved_by = None
                        alert.resolved_at = None
                        alert.resolution_notes = None
                        alert.updated_at = utc_now()
                        self.db.commit()
                        results["success"].append(alert.id)
                    else:
                        results["failed"].append({
                            "alert_id": alert.id,
                            "reason": "告警未解决"
                        })
                        
                else:
                    results["failed"].append({
                        "alert_id": alert.id,
                        "reason": f"不支持的操作: {operation_data.operation}"
                    })
                    
            except Exception as e:
                results["failed"].append({
                    "alert_id": alert.id,
                    "reason": str(e)
                })
        
        logger.info(f"✅ 批量操作完成: 成功 {len(results['success'])}, 失败 {len(results['failed'])}")
        return results
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取告警统计数据"""
        return self.alert_repository.get_statistics()
    
    def create_notification_channel(self, channel_data: NotificationChannelCreate, created_by: int) -> NotificationChannel:
        """创建通知渠道"""
        return self.channel_repository.create(channel_data, created_by)
    
    def get_notification_channel_by_id(self, channel_id: int) -> NotificationChannel:
        """根据ID获取通知渠道"""
        channel = self.channel_repository.get_by_id(channel_id)
        if not channel:
            raise NotFoundException("通知渠道", channel_id)
        return channel
    
    def update_notification_channel(self, channel_id: int, channel_data: NotificationChannelUpdate) -> NotificationChannel:
        """更新通知渠道"""
        channel = self.get_notification_channel_by_id(channel_id)
        return self.channel_repository.update(channel, channel_data)
    
    def test_alert_rule(self, request: TestAlertRequest) -> bool:
        """测试告警规则"""
        rule = self.get_alert_rule_by_id(request.rule_id)
        
        # 这里可以实现规则测试逻辑
        # 例如：根据测试数据验证条件表达式
        test_data = request.test_data or {}
        
        try:
            # 简单的条件表达式验证示例
            # 实际项目中需要更复杂的表达式解析器
            condition = rule.condition_expression
            
            # 模拟条件验证
            logger.info(f"✅ 告警规则测试: {rule.rule_name} - 条件: {condition}")
            return True
        except Exception as e:
            logger.error(f"❌ 告警规则测试失败: {e}")
            return False